Built with R version 4.4.0.
Wrangle site data
The idea with this initial step is to define the scale of our
samples. Contributors to the NFA did not define their SiteID’s and
EventID’s similar to each other, so we’ll need to distinguish between
SiteID vs EventID and make sure it’s consistent throughout the data.
I define a SiteID as a unique place in space, i.e., all
samples from the same ‘beach’ (will be defined later on). An EventID is
a unique pull of the beach seine. So there can be single or
multiple EventID’s associated with a SiteID. Additionally, I introduce a
VisitID, which adds a temporal distinction among SiteID’s, i.e., all
events from the same beach on the same day.
Set up
Load required packages, define directory, set options, source
scripts:
# Packages
library(tidyverse)
library(lubridate)
library(here)
library(skimr)
library(sf)
# Directory
wd = here()
dirs = wd %>% list.files() %>% str_subset(pattern = "^README|^LICENSE|.md$|.Rproj$", negate = TRUE)
for (i in seq_along(dirs)) {
name = str_replace_all(dirs[i], "^", "dir.")
path = str_replace_all(dirs[i], "^", str_c(wd, "/"))
assign(name, path)
rm(name, path, i)
}
# Options
# Source
Read in data
data = read_csv(file.path(dir.data, "FishAtlas_BeachSeines_2022.07.12.csv"),
show_col_types = FALSE)
GearLookup = read_csv(file.path(dir.data, "FishAtlasExpansion_040422_Lookup_Gear.csv"),
show_col_types = FALSE)
Separate site and
species info
As in typical community data (site x species), we have info tied to
site description and info tied to taxa. Notice that EventID is the
‘look-up’ key used in both data sets.
events.1 = data %>%
select(SiteID, EventID,
Date,
Lat, Lon = Long, Region, Location,
Habitat, TidalStage, Temp_C, Salinity,
GearSpecific, ProjectName, PointOfContact) %>%
mutate(Date = mdy(Date)) %>% # re-format date
distinct()
catch.1 = data %>%
select(EventID,
Sp_CommonName, Sp_ScientificName, Fam_CommonName, Fam_ScientificName,
Unmeasured, Length_mm, LengthType, LifeStage)
Considering gear
type
The NFA website makes it easy to filter for gear type, so I done
prior to downloading the .csv file. However, we’ll want to account for
differences among the beach seines used- namely the net mesh size. This
information is contained in the metadata for the NFA database and can be
accessed by request from the database managers (file
FishAtlasExpansion_040422_Lookup_Gear.csv). A few instances of
missing mesh size information was provided by email request to the
associated point of contact for that contributed data. Results from the
below code are hidden but comments explain what decisions were made.
# Join the mesh size info from our gear data to the site information
gear.1 = left_join(events.1, select(GearLookup, GearSpecific, MeshSize), by = "GearSpecific")
# Subset for gear related info and take a look
gear.2 = select(gear.1, EventID, MeshSize, GearSpecific, ProjectName, PointOfContact)
glimpse(gear.2)
# How many different mesh sizes are there?
gear.2$MeshSize %>% unique()
# Looks like we have an NA to take care of...
filter(gear.2, is.na(MeshSize))
# These are all from the GOAIERP project (PI Olav Ormseth). The report from that project reports 6 mm stretched mesh.
# We'll just go ahead and fix it here instead of changing the GearLookup file,
gear.3 = mutate(gear.2, MeshSize = ifelse(is.na(MeshSize), 6, MeshSize))
# Check our mesh sizes again,
gear.3$MeshSize %>% unique()
# Great, no more NA's.
# We can now join this information with our site data,
events.2 = left_join(events.1, select(gear.3, EventID, MeshSize), by = "EventID")
The “Site-Event”
problem
The catch data is tied to unique EventIDs which are associated with
spatially explicit SiteIDs (each SiteID has a unique lat/lon).
Considering that the data has been contributed by multiple
researchers/projects, we’ll need to make sure we have consistent sites
and events across the whole dataset. After that we can tackle the catch
data. First, we take a look at all of the site data with
skimr::skim().
skim(events.2)
Data summary
| Name |
events.2 |
| Number of rows |
4473 |
| Number of columns |
15 |
| _______________________ |
|
| Column type frequency: |
|
| character |
7 |
| Date |
1 |
| numeric |
7 |
| ________________________ |
|
| Group variables |
None |
Variable type: character
| Region |
0 |
1.00 |
10 |
16 |
0 |
5 |
0 |
| Location |
1 |
1.00 |
8 |
135 |
0 |
406 |
0 |
| Habitat |
0 |
1.00 |
4 |
13 |
0 |
8 |
0 |
| TidalStage |
1007 |
0.77 |
3 |
5 |
0 |
6 |
0 |
| GearSpecific |
0 |
1.00 |
8 |
12 |
0 |
15 |
0 |
| ProjectName |
0 |
1.00 |
4 |
31 |
0 |
31 |
0 |
| PointOfContact |
0 |
1.00 |
91 |
151 |
0 |
11 |
0 |
Variable type: Date
| Date |
0 |
1 |
1976-05-29 |
2021-09-09 |
2006-04-25 |
1035 |
Variable type: numeric
| SiteID |
0 |
1.00 |
1173.39 |
597.51 |
1.00 |
725.00 |
1091.00 |
1664.00 |
2505.00 |
▅▃▇▇▁ |
| EventID |
0 |
1.00 |
6345.33 |
3081.50 |
1.00 |
3613.00 |
6988.00 |
9176.00 |
10340.00 |
▃▃▁▇▇ |
| Lat |
0 |
1.00 |
59.66 |
3.58 |
51.64 |
58.33 |
59.40 |
59.60 |
71.39 |
▁▇▃▁▁ |
| Lon |
0 |
1.00 |
-145.21 |
9.86 |
-176.95 |
-151.63 |
-150.22 |
-134.95 |
-130.99 |
▁▁▇▁▇ |
| Temp_C |
1966 |
0.56 |
9.97 |
3.45 |
-0.92 |
7.40 |
10.50 |
12.50 |
28.70 |
▂▇▇▁▁ |
| Salinity |
1988 |
0.56 |
24.07 |
14.20 |
-400.00 |
19.80 |
25.11 |
30.10 |
73.50 |
▁▁▁▁▇ |
| MeshSize |
0 |
1.00 |
5.36 |
3.52 |
3.00 |
3.00 |
3.20 |
6.00 |
12.70 |
▇▂▁▁▂ |
In particular we want to get a sense of how EventIDs are associated
with SiteIDs and other variables placing them in space and time.


We see a lot of single-pull samples when events are grouped by SiteID
and Date, i.e., a visit. However, we can’t assume all of those
‘visits’ are comparable in scope. Projects differed in structure and
purpose, so what one researcher would consider a new site, another
researcher might call a replicate event to be combined with other events
within a single sample. I call this the “Site-Event” problem.
We see that the distribution of events becomes less severe when
grouped by Date and Location, which tells me that some of those
single-pull samples actually should be aggregated to be comparable to
other multi-pull samples. However, grouping by location may not be
accurate because of the loose definition of ‘Location’ (the levels of
Location also seem to vary in scale). Since location info is tied to
SiteID, we can’t just look at EventID’s and lat/lon. Instead, we’ll need
to figure out a way to combine events at the SiteID level.
Basically, we are trying to combine SiteID’s that are currently
unique but should have the same identifier, i.e., samples of the same
beach. From there, we can define a VisitID as a sample of the same beach
AND same day. Within a VisitID we have our EventID(s), i.e., single or
multiple replicates of seines pulled on the same beach on the same day,
which is the level of our catch data.
Using
sf to solve the “Site-Event” problem
Here is where we need to decide on how to define a ‘beach’. In other
words, what do we consider the spatial scale distinguishing one sample
from another? From my personal seining, one of my larger-distanced sites
was Anchor Point, where we’ve seined up to 800 m between first and last
replicate. So in my opinion, 1 km would be reasonably conservative
estimate to link replicate seines. Imagine seining by skiff- you could
hop between replicates ~1 km down beach and still consider it the same
site. In the below code, I define clusters of SiteID’s by grouping
points that are within 1000 m of at least one other SiteID.
# Make a new tibble containing SiteID geometries:
sites.sf = events.2 %>%
select(SiteID, Lat, Lon) %>%
# Create sf object from lat/lon:
st_as_sf(., coords = c("Lon", "Lat"), crs = 4326) %>% # WGS84
# Project into Alaska Albers 3338
st_transform(crs = 3338) %>%
distinct()
# Define a buffer of 1km around each point
sites.sf.buf = st_buffer(sites.sf, dist = 1000)
# Create a tibble with clusters of overlapping buffer areas
sites.sf.cl = sites.sf.buf %>%
st_union() %>% # unite buffer areas
st_cast(to = "POLYGON") %>% # turn them into polygon features
st_as_sf() %>% # return geometry set features to sfc
rownames_to_column(var = "Cluster") %>% # create col for cluster groups
mutate(Cluster = as.factor(Cluster)) # use factor class
# Assign SiteID points to buffer area clusters
sites.sf.cl.join = st_join(sites.sf, sites.sf.cl, left = TRUE)
# Drop sf class from joined data
sites.cl = st_drop_geometry(sites.sf.cl.join)
# See what we got:
glimpse(sites.cl)
## Rows: 1,178
## Columns: 2
## $ SiteID <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,…
## $ Cluster <fct> 327, 327, 327, 327, 327, 326, 326, 326, 326, 327, 327, 327, 32…
We now have a simple classification variable that can be joined back
with the site information.
events.3 = left_join(events.2, sites.cl, by = "SiteID")
However, this only takes into account the spatial component of our
larger goal of creating a unique VisitID identifier. Next, we’ll account
for the sample dates where SiteID’s within a cluster match.
# Create a date-cluster tibble containing location and event info to be combined,
orig = select(events.3, Date, Cluster, SiteID, EventID, Lat, Lon)
# Nest the df by Date and Cluster,
orig.nest = orig %>%
group_by(Date, Cluster) %>%
nest(Sites = SiteID,
Events = EventID,
Lats = Lat,
Lons = Lon) %>%
ungroup()
We essentially created a our new sample identifier (visit) in nesting
by date (day) and cluster (beach). To bring the data back to the EventID
level, we need to deal with samples that now have multiple SiteID’s and
locations, as well as preserve the EventID’s associated with the
original SiteID. This means we will be overwriting data, which is why I
called the above subset ‘orig’ and the below ‘new’.
new = orig.nest %>%
rowwise() %>% # Operates a row-at-a-time (per sample)
mutate(SiteID.cl = min(Sites),
Lat.mean = mean(Lats$Lat),
Lon.mean = mean(Lons$Lon)) %>%
select(-c(Sites, Lats, Lons)) %>% # Remove original info in nested variables
unite(col = VisitID, SiteID.cl, Date, sep = "_", remove = FALSE) %>% # create VisitID
select(-c(Date, SiteID.cl, Cluster)) %>% # Remove info now captured by VisitID
unnest_longer(Events) %>% # Unnest to the EventID level
unpack(cols = Events) # change tibble back to vector
# Join our new identifier to the rest if the site data,
visits = left_join(new, events.3, by = "EventID") %>%
mutate(Lat = Lat.mean, Lon = Lon.mean) %>% # Replace old lat/lon with new mean lat/lon
select(-c(Lat.mean, Lon.mean))
# Check our our new data structure
head(visits, 10)
## # A tibble: 10 × 17
## VisitID EventID SiteID Date Lat Lon Region Location Habitat
## <chr> <dbl> <dbl> <date> <dbl> <dbl> <chr> <chr> <chr>
## 1 1_2001-07-24 15 1 2001-07-24 58.6 -135. Gulf of … southea… Kelp
## 2 1_2001-07-24 16 2 2001-07-24 58.6 -135. Gulf of … southea… Kelp
## 3 1_2001-07-24 17 3 2001-07-24 58.6 -135. Gulf of … southea… Kelp
## 4 1_2001-07-24 18 4 2001-07-24 58.6 -135. Gulf of … southea… Sand-G…
## 5 1_2001-07-24 19 5 2001-07-24 58.6 -135. Gulf of … southea… Bedrock
## 6 1_2002-03-25 60 1 2002-03-25 58.6 -135. Gulf of … southea… Kelp
## 7 1_2002-03-25 61 2 2002-03-25 58.6 -135. Gulf of … southea… Kelp
## 8 1_2002-03-25 62 3 2002-03-25 58.6 -135. Gulf of … southea… Kelp
## 9 1_2002-03-25 63 4 2002-03-25 58.6 -135. Gulf of … southea… Sand-G…
## 10 1_2002-03-25 64 5 2002-03-25 58.6 -135. Gulf of … southea… Bedrock
## # ℹ 8 more variables: TidalStage <chr>, Temp_C <dbl>, Salinity <dbl>,
## # GearSpecific <chr>, ProjectName <chr>, PointOfContact <chr>,
## # MeshSize <dbl>, Cluster <fct>
We can see in first 10 rows how the data stuctured by VisitID
compares to the original. To select a beach identifier for the new
VisitID, I simply went with the lowest SiteID of the nest list (no wrong
answers here). SiteID is not very useful anymore, but I left it in the
data anyway. The locations to be combined are at most a handful kms
apart, so I figure a simple mean would suffice. Notice we now have
distinct locations at the VisitID level- this is because different
visits to the same beach might have had a different number of
replicates. For example, we see that VisitID 1_2001-07-24 involved the
first five rows (EventID’s 15-19), whereas, VisitID 1_2002-03-35 had an
additional two events.
As a last step, let’s return to our frequency plots showing the
number events per sample:


Wow. There are way less single-pull samples! Also, there are some
interesting samples with replicates of 9, 10, and 12.
LS0tCnRpdGxlOiAiTk9BQSBOZWFyc2hvcmUgRmlzaCBBdGxhcywgRGF0YSBXcmFuZ2xlIgphdXRob3I6ICJDaHJpcyBHdW8iCmRhdGU6ICJMYXN0IGNvbXBpbGVkIG9uIGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogVFJVRQogICAgdG9jX2RlcHRoOiAyCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogRkFMU0UKICAgICAgcHJpbnQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IFRSVUUKICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUKLS0tCgpgYGB7ciBpbmNsdWRlID0gRkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlID0gRkFMU0UpCmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nID0gRkFMU0UpCmtuaXRyOjpvcHRzX2NodW5rJHNldChzaXplID0gInNjcmlwdHNpemUiKQpgYGAKCkJ1aWx0IHdpdGggUiB2ZXJzaW9uIGByIGdldFJ2ZXJzaW9uKClgLgoKIyBJbnRybwoKSGVyZSwgSSBkb2N1bWVudCB0aGUgc3RlcHMgdGFrZW4gaW4gd3JhbmdsaW5nIHRoZSBOT0FBIE5lYXJzaG9yZSBGaXNoIEF0bGFzIChORkEpLiBUaGlzIHJlcGxhY2VzIHRoZSBzZXBhcmF0ZSBzY3JpcHRzIChuYW1lZCAiLi9GaXNoQXRsYXNcXyNcX2Rlc2NyaXB0aW9uLlIiKSBhbmQgY29tYmluZXMgdGhlbSBpbnRvIGEgc2luZ2xlLCBzdHJlYW1saW5lZCBSIG1hcmtkb3duIGZpbGUuIFRoZXNlIFIgc2NyaXB0cyB3aWxsIGJlIGFyY2hpdmVkIGluIGNhc2UgSSBuZWVkIHRvIHJlcGxpY2F0ZSBvbGRlciBtZXRob2RzLiBOYW1lbHksIEkgdXNlZCB0byB1c2UgKipyZ2RhbCoqIHBhY2thZ2UgZm9yIHNvbWUgc3RlcHMgaW4gdGhlIHdyYW5nbGluZyBwcm9jZXNzIGJ1dCB0aGF0IHBhY2thZ2Ugc3RvcHBlZCBiZWluZyBzdXBwb3J0ZWQgY2EuIE9jdCAyMDIzIGluIGxpZXUgb2YgdGhlICoqc2YqKiBwYWNrYWdlLgoKTGluayB0byB0aGUgTkZBIGNhbiBiZSBmb3VuZCBoZXJlLCA8aHR0cHM6Ly9hbGFza2FmaXNoZXJpZXMubm9hYS5nb3YvbWFwcGluZy9zei8+LiBUaGUgZW50aXJlIGRhdGFiYXNlIGNhbiBiZSBkb3dubG9hZGVkIGFzIGEgLmNzdiBmaWxlLCB3aGljaCBpcyB3aGF0IEkgdXNlIGhlcmUuIEhvd2V2ZXIsIEkgaGF2ZSBhZGRpdGlvbmFsIGRhdGEgZmlsZXMgdGhhdCB3ZXJlIGVpdGhlciBzaGFyZWQgd2l0aCBtZSBieSBORkEgY29udGVjdCBtYW5hZ2VycyBvciBtb2RpZmllZCBmcm9tIHRoZSBOT0FBIE5GQSBkYXRhIGRpcmVjdG9yeSBmb3IgZWFzZSBvZiB1cGxvYWRpbmcgaW50byBSLiBJIHRyeSB0byBkb2N1bWVudCB0aGVzZSBjYXNlcyBpbiB0aGUgZnV0dXJlLgoKIyBXcmFuZ2xlIHNpdGUgZGF0YQoKVGhlIGlkZWEgd2l0aCB0aGlzIGluaXRpYWwgc3RlcCBpcyB0byBkZWZpbmUgdGhlIHNjYWxlIG9mIG91ciBzYW1wbGVzLiBDb250cmlidXRvcnMgdG8gdGhlIE5GQSBkaWQgbm90IGRlZmluZSB0aGVpciBTaXRlSUQncyBhbmQgRXZlbnRJRCdzIHNpbWlsYXIgdG8gZWFjaCBvdGhlciwgc28gd2UnbGwgbmVlZCB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIFNpdGVJRCB2cyBFdmVudElEIGFuZCBtYWtlIHN1cmUgaXQncyBjb25zaXN0ZW50IHRocm91Z2hvdXQgdGhlIGRhdGEuCgpJIGRlZmluZSBhIFNpdGVJRCBhcyAqYSB1bmlxdWUgcGxhY2UgaW4gc3BhY2UqLCBpLmUuLCBhbGwgc2FtcGxlcyBmcm9tIHRoZSBzYW1lICdiZWFjaCcgKHdpbGwgYmUgZGVmaW5lZCBsYXRlciBvbikuIEFuIEV2ZW50SUQgaXMgKmEgdW5pcXVlIHB1bGwgb2YgdGhlIGJlYWNoIHNlaW5lKi4gU28gdGhlcmUgY2FuIGJlIHNpbmdsZSBvciBtdWx0aXBsZSBFdmVudElEJ3MgYXNzb2NpYXRlZCB3aXRoIGEgU2l0ZUlELiBBZGRpdGlvbmFsbHksIEkgaW50cm9kdWNlIGEgVmlzaXRJRCwgd2hpY2ggYWRkcyBhIHRlbXBvcmFsIGRpc3RpbmN0aW9uIGFtb25nIFNpdGVJRCdzLCBpLmUuLCAqYWxsIGV2ZW50cyBmcm9tIHRoZSBzYW1lIGJlYWNoIG9uIHRoZSBzYW1lIGRheSouCgojIyBTZXQgdXAKCkxvYWQgcmVxdWlyZWQgcGFja2FnZXMsIGRlZmluZSBkaXJlY3RvcnksIHNldCBvcHRpb25zLCBzb3VyY2Ugc2NyaXB0czoKCmBgYHtyfQojIFBhY2thZ2VzCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShoZXJlKQpsaWJyYXJ5KHNraW1yKQpsaWJyYXJ5KHNmKQoKIyBEaXJlY3RvcnkKd2QgPSBoZXJlKCkKZGlycyA9IHdkICU+JSBsaXN0LmZpbGVzKCkgJT4lIHN0cl9zdWJzZXQocGF0dGVybiA9ICJeUkVBRE1FfF5MSUNFTlNFfC5tZCR8LlJwcm9qJCIsIG5lZ2F0ZSA9IFRSVUUpCmZvciAoaSBpbiBzZXFfYWxvbmcoZGlycykpIHsKICBuYW1lID0gc3RyX3JlcGxhY2VfYWxsKGRpcnNbaV0sICJeIiwgImRpci4iKQogIHBhdGggPSBzdHJfcmVwbGFjZV9hbGwoZGlyc1tpXSwgIl4iLCBzdHJfYyh3ZCwgIi8iKSkKICBhc3NpZ24obmFtZSwgcGF0aCkKICBybShuYW1lLCBwYXRoLCBpKQp9CgojIE9wdGlvbnMKCiMgU291cmNlCgpgYGAKCiMjIFJlYWQgaW4gZGF0YQoKYGBge3J9CmRhdGEgPSByZWFkX2NzdihmaWxlLnBhdGgoZGlyLmRhdGEsICJGaXNoQXRsYXNfQmVhY2hTZWluZXNfMjAyMi4wNy4xMi5jc3YiKSwKICAgICAgICAgICAgICAgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkKR2Vhckxvb2t1cCA9IHJlYWRfY3N2KGZpbGUucGF0aChkaXIuZGF0YSwgIkZpc2hBdGxhc0V4cGFuc2lvbl8wNDA0MjJfTG9va3VwX0dlYXIuY3N2IiksCiAgICAgICAgICAgICAgICAgICAgICBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQpgYGAKCiMjIFNlcGFyYXRlIHNpdGUgYW5kIHNwZWNpZXMgaW5mbwoKQXMgaW4gdHlwaWNhbCBjb21tdW5pdHkgZGF0YSAoc2l0ZSB4IHNwZWNpZXMpLCB3ZSBoYXZlIGluZm8gdGllZCB0byBzaXRlIGRlc2NyaXB0aW9uIGFuZCBpbmZvIHRpZWQgdG8gdGF4YS4gTm90aWNlIHRoYXQgRXZlbnRJRCBpcyB0aGUgJ2xvb2stdXAnIGtleSB1c2VkIGluIGJvdGggZGF0YSBzZXRzLgoKYGBge3J9CmV2ZW50cy4xID0gZGF0YSAlPiUKICBzZWxlY3QoU2l0ZUlELCBFdmVudElELAogICAgICAgICBEYXRlLAogICAgICAgICBMYXQsIExvbiA9IExvbmcsIFJlZ2lvbiwgTG9jYXRpb24sCiAgICAgICAgIEhhYml0YXQsIFRpZGFsU3RhZ2UsIFRlbXBfQywgU2FsaW5pdHksCiAgICAgICAgIEdlYXJTcGVjaWZpYywgUHJvamVjdE5hbWUsIFBvaW50T2ZDb250YWN0KSAlPiUKICBtdXRhdGUoRGF0ZSA9IG1keShEYXRlKSkgJT4lICMgcmUtZm9ybWF0IGRhdGUKICBkaXN0aW5jdCgpCgpjYXRjaC4xID0gZGF0YSAlPiUKICBzZWxlY3QoRXZlbnRJRCwKICAgICAgICAgU3BfQ29tbW9uTmFtZSwgU3BfU2NpZW50aWZpY05hbWUsIEZhbV9Db21tb25OYW1lLCBGYW1fU2NpZW50aWZpY05hbWUsCiAgICAgICAgIFVubWVhc3VyZWQsIExlbmd0aF9tbSwgTGVuZ3RoVHlwZSwgTGlmZVN0YWdlKQpgYGAKCiMjIENvbnNpZGVyaW5nIGdlYXIgdHlwZQoKVGhlIE5GQSB3ZWJzaXRlIG1ha2VzIGl0IGVhc3kgdG8gZmlsdGVyIGZvciBnZWFyIHR5cGUsIHNvIEkgZG9uZSBwcmlvciB0byBkb3dubG9hZGluZyB0aGUgLmNzdiBmaWxlLiBIb3dldmVyLCB3ZSdsbCB3YW50IHRvIGFjY291bnQgZm9yIGRpZmZlcmVuY2VzIGFtb25nIHRoZSBiZWFjaCBzZWluZXMgdXNlZC0gbmFtZWx5IHRoZSBuZXQgbWVzaCBzaXplLiBUaGlzIGluZm9ybWF0aW9uIGlzIGNvbnRhaW5lZCBpbiB0aGUgbWV0YWRhdGEgZm9yIHRoZSBORkEgZGF0YWJhc2UgYW5kIGNhbiBiZSBhY2Nlc3NlZCBieSByZXF1ZXN0IGZyb20gdGhlIGRhdGFiYXNlIG1hbmFnZXJzIChmaWxlICpGaXNoQXRsYXNFeHBhbnNpb25fMDQwNDIyX0xvb2t1cF9HZWFyLmNzdiopLiBBIGZldyBpbnN0YW5jZXMgb2YgbWlzc2luZyBtZXNoIHNpemUgaW5mb3JtYXRpb24gd2FzIHByb3ZpZGVkIGJ5IGVtYWlsIHJlcXVlc3QgdG8gdGhlIGFzc29jaWF0ZWQgcG9pbnQgb2YgY29udGFjdCBmb3IgdGhhdCBjb250cmlidXRlZCBkYXRhLiBSZXN1bHRzIGZyb20gdGhlIGJlbG93IGNvZGUgYXJlIGhpZGRlbiBidXQgY29tbWVudHMgZXhwbGFpbiB3aGF0IGRlY2lzaW9ucyB3ZXJlIG1hZGUuCgpgYGB7ciByZXN1bHRzID0gJ2hpZGUnfQojIEpvaW4gdGhlIG1lc2ggc2l6ZSBpbmZvIGZyb20gb3VyIGdlYXIgZGF0YSB0byB0aGUgc2l0ZSBpbmZvcm1hdGlvbgpnZWFyLjEgPSBsZWZ0X2pvaW4oZXZlbnRzLjEsIHNlbGVjdChHZWFyTG9va3VwLCBHZWFyU3BlY2lmaWMsIE1lc2hTaXplKSwgYnkgPSAiR2VhclNwZWNpZmljIikKCiMgU3Vic2V0IGZvciBnZWFyIHJlbGF0ZWQgaW5mbyBhbmQgdGFrZSBhIGxvb2sKZ2Vhci4yID0gc2VsZWN0KGdlYXIuMSwgRXZlbnRJRCwgTWVzaFNpemUsIEdlYXJTcGVjaWZpYywgUHJvamVjdE5hbWUsIFBvaW50T2ZDb250YWN0KQpnbGltcHNlKGdlYXIuMikKIyBIb3cgbWFueSBkaWZmZXJlbnQgbWVzaCBzaXplcyBhcmUgdGhlcmU/CmdlYXIuMiRNZXNoU2l6ZSAlPiUgdW5pcXVlKCkKCiMgTG9va3MgbGlrZSB3ZSBoYXZlIGFuIE5BIHRvIHRha2UgY2FyZSBvZi4uLgpmaWx0ZXIoZ2Vhci4yLCBpcy5uYShNZXNoU2l6ZSkpCiMgVGhlc2UgYXJlIGFsbCBmcm9tIHRoZSBHT0FJRVJQIHByb2plY3QgKFBJIE9sYXYgT3Jtc2V0aCkuIFRoZSByZXBvcnQgZnJvbSB0aGF0IHByb2plY3QgcmVwb3J0cyA2IG1tIHN0cmV0Y2hlZCBtZXNoLgojIFdlJ2xsIGp1c3QgZ28gYWhlYWQgYW5kIGZpeCBpdCBoZXJlIGluc3RlYWQgb2YgY2hhbmdpbmcgdGhlIEdlYXJMb29rdXAgZmlsZSwKZ2Vhci4zID0gbXV0YXRlKGdlYXIuMiwgTWVzaFNpemUgPSBpZmVsc2UoaXMubmEoTWVzaFNpemUpLCA2LCBNZXNoU2l6ZSkpCgojIENoZWNrIG91ciBtZXNoIHNpemVzIGFnYWluLApnZWFyLjMkTWVzaFNpemUgJT4lIHVuaXF1ZSgpCiMgR3JlYXQsIG5vIG1vcmUgTkEncy4KCiMgV2UgY2FuIG5vdyBqb2luIHRoaXMgaW5mb3JtYXRpb24gd2l0aCBvdXIgc2l0ZSBkYXRhLApldmVudHMuMiA9IGxlZnRfam9pbihldmVudHMuMSwgc2VsZWN0KGdlYXIuMywgRXZlbnRJRCwgTWVzaFNpemUpLCBieSA9ICJFdmVudElEIikKYGBgCgojIyBUaGUgIlNpdGUtRXZlbnQiIHByb2JsZW0KClRoZSBjYXRjaCBkYXRhIGlzIHRpZWQgdG8gdW5pcXVlIEV2ZW50SURzIHdoaWNoIGFyZSBhc3NvY2lhdGVkIHdpdGggc3BhdGlhbGx5IGV4cGxpY2l0IFNpdGVJRHMgKGVhY2ggU2l0ZUlEIGhhcyBhIHVuaXF1ZSBsYXQvbG9uKS4gQ29uc2lkZXJpbmcgdGhhdCB0aGUgZGF0YSBoYXMgYmVlbiBjb250cmlidXRlZCBieSBtdWx0aXBsZSByZXNlYXJjaGVycy9wcm9qZWN0cywgd2UnbGwgbmVlZCB0byBtYWtlIHN1cmUgd2UgaGF2ZSBjb25zaXN0ZW50IHNpdGVzIGFuZCBldmVudHMgYWNyb3NzIHRoZSB3aG9sZSBkYXRhc2V0LiBBZnRlciB0aGF0IHdlIGNhbiB0YWNrbGUgdGhlIGNhdGNoIGRhdGEuIEZpcnN0LCB3ZSB0YWtlIGEgbG9vayBhdCBhbGwgb2YgdGhlIHNpdGUgZGF0YSB3aXRoICoqc2tpbXI6OnNraW0oKSoqLgoKYGBge3J9CnNraW0oZXZlbnRzLjIpCmBgYAoKSW4gcGFydGljdWxhciB3ZSB3YW50IHRvIGdldCBhIHNlbnNlIG9mIGhvdyBFdmVudElEcyBhcmUgYXNzb2NpYXRlZCB3aXRoIFNpdGVJRHMgYW5kIG90aGVyIHZhcmlhYmxlcyBwbGFjaW5nIHRoZW0gaW4gc3BhY2UgYW5kIHRpbWUuCgpgYGB7ciBlY2hvID0gRkFMU0V9CmV2ZW50cy4yICU+JSBncm91cF9ieShTaXRlSUQsIERhdGUpICU+JSBzdW1tYXJpc2UoZXZlbnRzID0gbl9kaXN0aW5jdChFdmVudElEKSkgJT4lCiAgZ2dwbG90KGRhdGEgPSAuLCBhZXMoeCA9IGV2ZW50cykpICsKICBnZW9tX2JhcihhZXMoeSA9IGFmdGVyX3N0YXQoY291bnQpKSkgKwogIGdlb21fdGV4dChzdGF0ID0gJ2NvdW50JywgYWVzKGxhYmVsID0gYWZ0ZXJfc3RhdChjb3VudCkpLCB2anVzdCA9IC0wLjUpICsKICBsYWJzKHRpdGxlID0gIkZyZXF1ZW5jeSBvZiBTaXRlSUQtRGF0ZSBwYWlycyBieSAjIG9mIGV2ZW50cyAocmVwbGljYXRlcykiKQoKZXZlbnRzLjIgJT4lIGdyb3VwX2J5KERhdGUsIExvY2F0aW9uKSAlPiUgc3VtbWFyaXNlKGV2ZW50cyA9IG5fZGlzdGluY3QoRXZlbnRJRCkpICU+JQogIGdncGxvdChkYXRhID0gLiwgYWVzKHggPSBldmVudHMpKSArCiAgZ2VvbV9iYXIoYWVzKHkgPSBhZnRlcl9zdGF0KGNvdW50KSkpICsKICBnZW9tX3RleHQoc3RhdCA9ICdjb3VudCcsIGFlcyhsYWJlbCA9IGFmdGVyX3N0YXQoY291bnQpKSwgdmp1c3QgPSAtMC41KSArCiAgbGFicyh0aXRsZSA9ICJGcmVxdWVuY3kgb2YgRGF0ZS1Mb2NhdGlvbiBwYWlycyB3aXRoICMgb2YgZXZlbnRzIChyZXBsaWNhdGVzKSIpCmBgYAoKV2Ugc2VlIGEgbG90IG9mIHNpbmdsZS1wdWxsIHNhbXBsZXMgd2hlbiBldmVudHMgYXJlIGdyb3VwZWQgYnkgU2l0ZUlEIGFuZCBEYXRlLCBpLmUuLCBhICp2aXNpdCouIEhvd2V2ZXIsIHdlIGNhbid0IGFzc3VtZSBhbGwgb2YgdGhvc2UgJ3Zpc2l0cycgYXJlIGNvbXBhcmFibGUgaW4gc2NvcGUuIFByb2plY3RzIGRpZmZlcmVkIGluIHN0cnVjdHVyZSBhbmQgcHVycG9zZSwgc28gd2hhdCBvbmUgcmVzZWFyY2hlciB3b3VsZCBjb25zaWRlciBhIG5ldyBzaXRlLCBhbm90aGVyIHJlc2VhcmNoZXIgbWlnaHQgY2FsbCBhIHJlcGxpY2F0ZSBldmVudCB0byBiZSBjb21iaW5lZCB3aXRoIG90aGVyIGV2ZW50cyB3aXRoaW4gYSBzaW5nbGUgc2FtcGxlLiBJIGNhbGwgdGhpcyB0aGUgIlNpdGUtRXZlbnQiIHByb2JsZW0uCgpXZSBzZWUgdGhhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGV2ZW50cyBiZWNvbWVzIGxlc3Mgc2V2ZXJlIHdoZW4gZ3JvdXBlZCBieSBEYXRlIGFuZCBMb2NhdGlvbiwgd2hpY2ggdGVsbHMgbWUgdGhhdCBzb21lIG9mIHRob3NlIHNpbmdsZS1wdWxsIHNhbXBsZXMgYWN0dWFsbHkgc2hvdWxkIGJlIGFnZ3JlZ2F0ZWQgdG8gYmUgY29tcGFyYWJsZSB0byBvdGhlciBtdWx0aS1wdWxsIHNhbXBsZXMuIEhvd2V2ZXIsIGdyb3VwaW5nIGJ5IGxvY2F0aW9uIG1heSBub3QgYmUgYWNjdXJhdGUgYmVjYXVzZSBvZiB0aGUgbG9vc2UgZGVmaW5pdGlvbiBvZiAnTG9jYXRpb24nICh0aGUgbGV2ZWxzIG9mIExvY2F0aW9uIGFsc28gc2VlbSB0byB2YXJ5IGluIHNjYWxlKS4gU2luY2UgbG9jYXRpb24gaW5mbyBpcyB0aWVkIHRvIFNpdGVJRCwgd2UgY2FuJ3QganVzdCBsb29rIGF0IEV2ZW50SUQncyBhbmQgbGF0L2xvbi4gSW5zdGVhZCwgd2UnbGwgbmVlZCB0byBmaWd1cmUgb3V0IGEgd2F5IHRvIGNvbWJpbmUgZXZlbnRzIGF0IHRoZSBTaXRlSUQgbGV2ZWwuCgpCYXNpY2FsbHksIHdlIGFyZSB0cnlpbmcgdG8gY29tYmluZSBTaXRlSUQncyB0aGF0IGFyZSBjdXJyZW50bHkgdW5pcXVlIGJ1dCBzaG91bGQgaGF2ZSB0aGUgc2FtZSBpZGVudGlmaWVyLCBpLmUuLCBzYW1wbGVzIG9mIHRoZSBzYW1lIGJlYWNoLiBGcm9tIHRoZXJlLCB3ZSBjYW4gZGVmaW5lIGEgVmlzaXRJRCBhcyBhIHNhbXBsZSBvZiB0aGUgc2FtZSBiZWFjaCBBTkQgc2FtZSBkYXkuIFdpdGhpbiBhIFZpc2l0SUQgd2UgaGF2ZSBvdXIgRXZlbnRJRChzKSwgaS5lLiwgc2luZ2xlIG9yIG11bHRpcGxlIHJlcGxpY2F0ZXMgb2Ygc2VpbmVzIHB1bGxlZCBvbiB0aGUgc2FtZSBiZWFjaCBvbiB0aGUgc2FtZSBkYXksIHdoaWNoIGlzIHRoZSBsZXZlbCBvZiBvdXIgY2F0Y2ggZGF0YS4KCiMjIFVzaW5nICoqc2YqKiB0byBzb2x2ZSB0aGUgIlNpdGUtRXZlbnQiIHByb2JsZW0KCkhlcmUgaXMgd2hlcmUgd2UgbmVlZCB0byBkZWNpZGUgb24gaG93IHRvIGRlZmluZSBhICdiZWFjaCcuIEluIG90aGVyIHdvcmRzLCB3aGF0IGRvIHdlIGNvbnNpZGVyIHRoZSBzcGF0aWFsIHNjYWxlIGRpc3Rpbmd1aXNoaW5nIG9uZSBzYW1wbGUgZnJvbSBhbm90aGVyPyBGcm9tIG15IHBlcnNvbmFsIHNlaW5pbmcsIG9uZSBvZiBteSBsYXJnZXItZGlzdGFuY2VkIHNpdGVzIHdhcyBBbmNob3IgUG9pbnQsIHdoZXJlIHdlJ3ZlIHNlaW5lZCB1cCB0byA4MDAgbSBiZXR3ZWVuIGZpcnN0IGFuZCBsYXN0IHJlcGxpY2F0ZS4gU28gaW4gbXkgb3BpbmlvbiwgMSBrbSB3b3VsZCBiZSByZWFzb25hYmx5IGNvbnNlcnZhdGl2ZSBlc3RpbWF0ZSB0byBsaW5rIHJlcGxpY2F0ZSBzZWluZXMuIEltYWdpbmUgc2VpbmluZyBieSBza2lmZi0geW91IGNvdWxkIGhvcCBiZXR3ZWVuIHJlcGxpY2F0ZXMgXH4xIGttIGRvd24gYmVhY2ggYW5kIHN0aWxsIGNvbnNpZGVyIGl0IHRoZSBzYW1lIHNpdGUuIEluIHRoZSBiZWxvdyBjb2RlLCBJIGRlZmluZSBjbHVzdGVycyBvZiBTaXRlSUQncyBieSBncm91cGluZyBwb2ludHMgdGhhdCBhcmUgd2l0aGluIDEwMDAgbSBvZiBhdCBsZWFzdCBvbmUgb3RoZXIgU2l0ZUlELgoKYGBge3J9CiMgTWFrZSBhIG5ldyB0aWJibGUgY29udGFpbmluZyBTaXRlSUQgZ2VvbWV0cmllczoKc2l0ZXMuc2YgPSBldmVudHMuMiAlPiUKICBzZWxlY3QoU2l0ZUlELCBMYXQsIExvbikgJT4lCiAgIyBDcmVhdGUgc2Ygb2JqZWN0IGZyb20gbGF0L2xvbjoKICBzdF9hc19zZiguLCBjb29yZHMgPSBjKCJMb24iLCAiTGF0IiksIGNycyA9IDQzMjYpICU+JSAjIFdHUzg0CiAgIyBQcm9qZWN0IGludG8gQWxhc2thIEFsYmVycyAzMzM4CiAgc3RfdHJhbnNmb3JtKGNycyA9IDMzMzgpICU+JQogIGRpc3RpbmN0KCkKCiMgRGVmaW5lIGEgYnVmZmVyIG9mIDFrbSBhcm91bmQgZWFjaCBwb2ludApzaXRlcy5zZi5idWYgPSBzdF9idWZmZXIoc2l0ZXMuc2YsIGRpc3QgPSAxMDAwKQoKIyBDcmVhdGUgYSB0aWJibGUgd2l0aCBjbHVzdGVycyBvZiBvdmVybGFwcGluZyBidWZmZXIgYXJlYXMgCnNpdGVzLnNmLmNsID0gc2l0ZXMuc2YuYnVmICU+JQogIHN0X3VuaW9uKCkgJT4lICMgdW5pdGUgYnVmZmVyIGFyZWFzCiAgc3RfY2FzdCh0byA9ICJQT0xZR09OIikgJT4lICMgdHVybiB0aGVtIGludG8gcG9seWdvbiBmZWF0dXJlcwogIHN0X2FzX3NmKCkgJT4lICMgcmV0dXJuIGdlb21ldHJ5IHNldCBmZWF0dXJlcyB0byBzZmMKICByb3duYW1lc190b19jb2x1bW4odmFyID0gIkNsdXN0ZXIiKSAlPiUgIyBjcmVhdGUgY29sIGZvciBjbHVzdGVyIGdyb3VwcwogIG11dGF0ZShDbHVzdGVyID0gYXMuZmFjdG9yKENsdXN0ZXIpKSAjIHVzZSBmYWN0b3IgY2xhc3MKCiMgQXNzaWduIFNpdGVJRCBwb2ludHMgdG8gYnVmZmVyIGFyZWEgY2x1c3RlcnMKc2l0ZXMuc2YuY2wuam9pbiA9IHN0X2pvaW4oc2l0ZXMuc2YsIHNpdGVzLnNmLmNsLCBsZWZ0ID0gVFJVRSkKCiMgRHJvcCBzZiBjbGFzcyBmcm9tIGpvaW5lZCBkYXRhCnNpdGVzLmNsID0gc3RfZHJvcF9nZW9tZXRyeShzaXRlcy5zZi5jbC5qb2luKQoKIyBTZWUgd2hhdCB3ZSBnb3Q6CmdsaW1wc2Uoc2l0ZXMuY2wpCmBgYAoKV2Ugbm93IGhhdmUgYSBzaW1wbGUgY2xhc3NpZmljYXRpb24gdmFyaWFibGUgdGhhdCBjYW4gYmUgam9pbmVkIGJhY2sgd2l0aCB0aGUgc2l0ZSBpbmZvcm1hdGlvbi4KCmBgYHtyfQpldmVudHMuMyA9IGxlZnRfam9pbihldmVudHMuMiwgc2l0ZXMuY2wsIGJ5ID0gIlNpdGVJRCIpCmBgYAoKSG93ZXZlciwgdGhpcyBvbmx5IHRha2VzIGludG8gYWNjb3VudCB0aGUgc3BhdGlhbCBjb21wb25lbnQgb2Ygb3VyIGxhcmdlciBnb2FsIG9mIGNyZWF0aW5nIGEgdW5pcXVlIFZpc2l0SUQgaWRlbnRpZmllci4gTmV4dCwgd2UnbGwgYWNjb3VudCBmb3IgdGhlIHNhbXBsZSBkYXRlcyB3aGVyZSBTaXRlSUQncyB3aXRoaW4gYSBjbHVzdGVyIG1hdGNoLgoKYGBge3J9CiMgQ3JlYXRlIGEgZGF0ZS1jbHVzdGVyIHRpYmJsZSBjb250YWluaW5nIGxvY2F0aW9uIGFuZCBldmVudCBpbmZvIHRvIGJlIGNvbWJpbmVkLApvcmlnID0gc2VsZWN0KGV2ZW50cy4zLCBEYXRlLCBDbHVzdGVyLCBTaXRlSUQsIEV2ZW50SUQsIExhdCwgTG9uKQoKIyBOZXN0IHRoZSBkZiBieSBEYXRlIGFuZCBDbHVzdGVyLApvcmlnLm5lc3QgPSBvcmlnICU+JQogIGdyb3VwX2J5KERhdGUsIENsdXN0ZXIpICU+JQogIG5lc3QoU2l0ZXMgPSBTaXRlSUQsCiAgICAgICBFdmVudHMgPSBFdmVudElELAogICAgICAgTGF0cyA9IExhdCwKICAgICAgIExvbnMgPSBMb24pICU+JQogIHVuZ3JvdXAoKQpgYGAKCldlIGVzc2VudGlhbGx5IGNyZWF0ZWQgYSBvdXIgbmV3IHNhbXBsZSBpZGVudGlmaWVyICh2aXNpdCkgaW4gbmVzdGluZyBieSBkYXRlIChkYXkpIGFuZCBjbHVzdGVyIChiZWFjaCkuIFRvIGJyaW5nIHRoZSBkYXRhIGJhY2sgdG8gdGhlIEV2ZW50SUQgbGV2ZWwsIHdlIG5lZWQgdG8gZGVhbCB3aXRoIHNhbXBsZXMgdGhhdCBub3cgaGF2ZSBtdWx0aXBsZSBTaXRlSUQncyBhbmQgbG9jYXRpb25zLCBhcyB3ZWxsIGFzIHByZXNlcnZlIHRoZSBFdmVudElEJ3MgYXNzb2NpYXRlZCB3aXRoIHRoZSBvcmlnaW5hbCBTaXRlSUQuIFRoaXMgbWVhbnMgd2Ugd2lsbCBiZSBvdmVyd3JpdGluZyBkYXRhLCB3aGljaCBpcyB3aHkgSSBjYWxsZWQgdGhlIGFib3ZlIHN1YnNldCAnb3JpZycgYW5kIHRoZSBiZWxvdyAnbmV3Jy4KCmBgYHtyfQpuZXcgPSBvcmlnLm5lc3QgJT4lIAogIHJvd3dpc2UoKSAlPiUgIyBPcGVyYXRlcyBhIHJvdy1hdC1hLXRpbWUgKHBlciBzYW1wbGUpCiAgbXV0YXRlKFNpdGVJRC5jbCA9IG1pbihTaXRlcyksIAogICAgICAgICBMYXQubWVhbiA9IG1lYW4oTGF0cyRMYXQpLAogICAgICAgICBMb24ubWVhbiA9IG1lYW4oTG9ucyRMb24pKSAlPiUKICBzZWxlY3QoLWMoU2l0ZXMsIExhdHMsIExvbnMpKSAlPiUgIyBSZW1vdmUgb3JpZ2luYWwgaW5mbyBpbiBuZXN0ZWQgdmFyaWFibGVzCiAgdW5pdGUoY29sID0gVmlzaXRJRCwgU2l0ZUlELmNsLCBEYXRlLCBzZXAgPSAiXyIsIHJlbW92ZSA9IEZBTFNFKSAlPiUgIyBjcmVhdGUgVmlzaXRJRAogIHNlbGVjdCgtYyhEYXRlLCBTaXRlSUQuY2wsIENsdXN0ZXIpKSAlPiUgIyBSZW1vdmUgaW5mbyBub3cgY2FwdHVyZWQgYnkgVmlzaXRJRAogIHVubmVzdF9sb25nZXIoRXZlbnRzKSAlPiUgIyBVbm5lc3QgdG8gdGhlIEV2ZW50SUQgbGV2ZWwKICB1bnBhY2soY29scyA9IEV2ZW50cykgIyBjaGFuZ2UgdGliYmxlIGJhY2sgdG8gdmVjdG9yCgojIEpvaW4gb3VyIG5ldyBpZGVudGlmaWVyIHRvIHRoZSByZXN0IGlmIHRoZSBzaXRlIGRhdGEsCnZpc2l0cyA9IGxlZnRfam9pbihuZXcsIGV2ZW50cy4zLCBieSA9ICJFdmVudElEIikgJT4lCiAgbXV0YXRlKExhdCA9IExhdC5tZWFuLCBMb24gPSBMb24ubWVhbikgJT4lICMgUmVwbGFjZSBvbGQgbGF0L2xvbiB3aXRoIG5ldyBtZWFuIGxhdC9sb24KICBzZWxlY3QoLWMoTGF0Lm1lYW4sIExvbi5tZWFuKSkKCiMgQ2hlY2sgb3VyIG91ciBuZXcgZGF0YSBzdHJ1Y3R1cmUKaGVhZCh2aXNpdHMsIDEwKQpgYGAKCldlIGNhbiBzZWUgaW4gZmlyc3QgMTAgcm93cyBob3cgdGhlIGRhdGEgc3R1Y3R1cmVkIGJ5IFZpc2l0SUQgY29tcGFyZXMgdG8gdGhlIG9yaWdpbmFsLiBUbyBzZWxlY3QgYSBiZWFjaCBpZGVudGlmaWVyIGZvciB0aGUgbmV3IFZpc2l0SUQsIEkgc2ltcGx5IHdlbnQgd2l0aCB0aGUgbG93ZXN0IFNpdGVJRCBvZiB0aGUgbmVzdCBsaXN0IChubyB3cm9uZyBhbnN3ZXJzIGhlcmUpLiBTaXRlSUQgaXMgbm90IHZlcnkgdXNlZnVsIGFueW1vcmUsIGJ1dCBJIGxlZnQgaXQgaW4gdGhlIGRhdGEgYW55d2F5LiBUaGUgbG9jYXRpb25zIHRvIGJlIGNvbWJpbmVkIGFyZSBhdCBtb3N0IGEgaGFuZGZ1bCBrbXMgYXBhcnQsIHNvIEkgZmlndXJlIGEgc2ltcGxlIG1lYW4gd291bGQgc3VmZmljZS4gTm90aWNlIHdlIG5vdyBoYXZlIGRpc3RpbmN0IGxvY2F0aW9ucyBhdCB0aGUgVmlzaXRJRCBsZXZlbC0gdGhpcyBpcyBiZWNhdXNlIGRpZmZlcmVudCB2aXNpdHMgdG8gdGhlIHNhbWUgYmVhY2ggbWlnaHQgaGF2ZSBoYWQgYSBkaWZmZXJlbnQgbnVtYmVyIG9mIHJlcGxpY2F0ZXMuIEZvciBleGFtcGxlLCB3ZSBzZWUgdGhhdCBWaXNpdElEIDFfMjAwMS0wNy0yNCBpbnZvbHZlZCB0aGUgZmlyc3QgZml2ZSByb3dzIChFdmVudElEJ3MgMTUtMTkpLCB3aGVyZWFzLCBWaXNpdElEIDFfMjAwMi0wMy0zNSBoYWQgYW4gYWRkaXRpb25hbCB0d28gZXZlbnRzLgoKQXMgYSBsYXN0IHN0ZXAsIGxldCdzIHJldHVybiB0byBvdXIgZnJlcXVlbmN5IHBsb3RzIHNob3dpbmcgdGhlIG51bWJlciBldmVudHMgcGVyIHNhbXBsZToKCmBgYHtyIGVjaG8gPSBGQUxTRX0KIyBQbG90IGV2ZW50cyBwZXIgU2l0ZUlELURhdGUgc2FtZSBhcyBiZWZvcmUsCmV2ZW50cy4zICU+JSBncm91cF9ieShTaXRlSUQsIERhdGUpICU+JSBzdW1tYXJpc2UoZXZlbnRzID0gbl9kaXN0aW5jdChFdmVudElEKSkgJT4lCiAgZ2dwbG90KGRhdGEgPSAuLCBhZXMoeCA9IGV2ZW50cykpICsKICBnZW9tX2JhcihhZXMoeSA9IGFmdGVyX3N0YXQoY291bnQpKSkgKwogIGdlb21fdGV4dChzdGF0ID0gJ2NvdW50JywgYWVzKGxhYmVsID0gYWZ0ZXJfc3RhdChjb3VudCkpLCB2anVzdCA9IC0wLjUpICsKICBsYWJzKHRpdGxlID0gIkZyZXF1ZW5jeSBvZiBTaXRlSUQtRGF0ZSBwYWlycyBieSAjIG9mIGV2ZW50cyAocmVwbGljYXRlcykiKQojIGdnc2F2ZSgibmZhX2ZyZXEtU2l0ZSZEYXRlLWJ5LXNlaW5lcy5wbmciLCBwbG90ID0gbGFzdF9wbG90KCksIGRldmljZSA9ICdwbmcnLCBwYXRoID0gZmlsZS5wYXRoKGRpci5maWdzKSkKCiMgQW5kIGV2ZW50cyBwZXIgdmlzaXQKdmlzaXRzICU+JSBncm91cF9ieShWaXNpdElEKSAlPiUgc3VtbWFyaXNlKGV2ZW50cyA9IG5fZGlzdGluY3QoRXZlbnRJRCkpICU+JQogIGdncGxvdChkYXRhID0gLiwgYWVzKHggPSBldmVudHMpKSArCiAgZ2VvbV9iYXIoYWVzKHkgPSBhZnRlcl9zdGF0KGNvdW50KSkpICsKICBnZW9tX3RleHQoc3RhdCA9ICdjb3VudCcsIGFlcyhsYWJlbCA9IGFmdGVyX3N0YXQoY291bnQpKSwgdmp1c3QgPSAtMC41KSArCiAgbGFicyh0aXRsZSA9ICJGcmVxdWVuY3kgb2YgdmlzaXRzIGJ5ICMgb2YgZXZlbnRzIChyZXBsaWNhdGVzKSIpCiMgZ2dzYXZlKCJuZmFfZnJlcS12aXNpdHMtYnktc2VpbmVzLnBuZyIsIHBsb3QgPSBsYXN0X3Bsb3QoKSwgZGV2aWNlID0gJ3BuZycsIHBhdGggPSBmaWxlLnBhdGgoZGlyLmZpZ3MpKQpgYGAKCldvdy4gVGhlcmUgYXJlIHdheSBsZXNzIHNpbmdsZS1wdWxsIHNhbXBsZXMhIEFsc28sIHRoZXJlIGFyZSBzb21lIGludGVyZXN0aW5nIHNhbXBsZXMgd2l0aCByZXBsaWNhdGVzIG9mIDksIDEwLCBhbmQgMTIuCgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgQ2xlYW4gdXAgb3VyIGVudmlyb25tZW50IGZvciB0aGUgbmV4dCBzdGVwOgpybShsaXN0ID0gbHMoKVshbHMoKSAlaW4lIGMoJ3Zpc2l0cycsICdjYXRjaC4xJywgJ2RhdGEnKV0pCgojIFJlc2V0IGRpcmVjdG9yeQp3ZCA9IGhlcmUoKQpkaXJzID0gd2QgJT4lIGxpc3QuZmlsZXMoKSAlPiUgc3RyX3N1YnNldChwYXR0ZXJuID0gIl5SRUFETUV8XkxJQ0VOU0V8Lm1kJHwuUnByb2okIiwgbmVnYXRlID0gVFJVRSkKZm9yIChpIGluIHNlcV9hbG9uZyhkaXJzKSkgewogIG5hbWUgPSBzdHJfcmVwbGFjZV9hbGwoZGlyc1tpXSwgIl4iLCAiZGlyLiIpCiAgcGF0aCA9IHN0cl9yZXBsYWNlX2FsbChkaXJzW2ldLCAiXiIsIHN0cl9jKHdkLCAiLyIpKQogIGFzc2lnbihuYW1lLCBwYXRoKQogIHJtKHBhdGgsIGkpCn0KYGBgCgojIFdyYW5nbGUgY2F0Y2ggZGF0YQoKU2ltaWxhciB0byBvdXIgd3JhbmdsZSBvZiBzaXRlIGluZm9ybWF0aW9uLCB3ZSB3YW50IHRvIGhvbmUgdGhlIGJyZWFkdGggb2YgdGhlIGNhdGNoIGRhdGEgd2UgdXNlLiBBdCB0aGlzIHN0YWdlLCB3ZSBkb24ndCB3YW50IHRvIG1ha2UgYW55ICppbnRlcnByZXRhdGlvbnMqIGFib3V0IHRoZSBjYXRjaC4gSW5zdGVhZCwgdGhlIGdvYWwgaGVyZSBpcyB0byB3ZWVkIG91dCBvYmplY3RpdmVseSB1bm5lZWRlZCBhbmQgc3VzcGljaW91cyBjYXNlcyBhbmQgZW5zdXJlIHRoZSBjb25zaXN0ZW5jeSBvZiB0aGUgZGF0YSAoZS5nLiwgYXJlIGFsbCBwb3NzaWJsZSBzcGVjaWVzIG5hbWVkIGFjdHVhbCBuYW1lcz8pLgoKIyMgU2V0IHVwCgpJZiBpdCB3ZXJlIG5lY2Vzc2FyeSB3ZSB3b3VsZCBsb2FkIGFkZGl0aW9uYWwgcGFja2FnZXMsIGRlZmluZSBkaXJlY3Rvcmllcywgc2V0IG9wdGlvbnMsIHNvdXJjZSBzY3JpcHRzLiBCdXQgd2UgZG8gbm90IGhhdmUgYW55IGFkZGl0aW9uYWwgc2V0IHVwIHRvIGRvIGF0IHRoaXMgcG9pbnQuCgpgYGB7ciBlY2hvID0gRkFMU0V9CiMgUGFja2FnZXMKCiMgRGlyZWN0b3J5CgojIE9wdGlvbnMKCiMgU291cmNlCgpgYGAKCiMjIFJlYWQgaW4gZGF0YQoKTm90aGluZyB0byBkbyBoZXJlLgoKIyMgRWRpaW5nIHRheG9ub215CgpgYGB7cn0Kc2tpbShjYXRjaC4xKQpgYGAKCk9uZSBuaWNlIHRoaW5nIGFib3V0ICoqc2tpbSgpKiogaXMgdGhhdCBpdCBxdWlja2x5IHRlbGxzIHlvdSB3aGVyZSB0aGUgaW5mb3JtYXRpb24gaXMgbWlzc2luZyBhbmQgaG93IG11Y2ggaXMgbWlzc2luZy4gV2Ugc2VlIHRoYXQgdGhlcmUgYXJlIG5pbmUgY2FzZXMgb2YgbWlzc2luZyBkYXRhIGF0IHRoZSBmYW1pbHkgbGV2ZWwuIFNvbWV0aGluZyBlbHNlIHRoYXQganVtcHMgb3V0IHRvIG1lIGlzIHRoYXQgdGhlIG51bWJlciBvZiB1bmlxdWUgc3BlY2llcyBjb21tb24gbmFtZXMgaXMgbm90IHRoZSBzYW1lIGFzIHRoZSBudW1iZXIgb2YgdW5pcXVlIHNwZWNpZXMgc2NpZW50aWZpYyBuYW1lcy4KCkknbGwgYWxzbyBjaGFuZ2UgdGhlICdVbm1lYXN1cmVkJyB2YXJpYWJsZSB0byBhIGNvdW50IGFidW5kYW5jZSwgd2hpY2ggbWF5IG5vdCBiZSB0b3RhbGx5IG5lY2Vzc2FyeSBidXQgd2lsbCBtYWtlIGl0IGVhc2llciBmb3IgbWUgdG8gd29yayB3aXRoIHRoZSBkYXRhLgoKQW5vdGhlciB0aGluZyB0byBwb2ludCBvdXQgaXMgdGhhdCBsZXNzIHRoYW4gaGFsZiBvZiB0aGUgZGF0YSBhcHBlYXJzIHRvIGhhdmUgbGlmZSBzdGFnZSBpbmZvcm1hdGlvbi4gRnVydGhlcm1vcmUsIHRoZSBkYXRhIHdpdGggbGVuZ3RoIGluZm9ybWF0aW9uIGlzIGEgbGl0dGxlIG92ZXIgNTAlLCB3aGljaCBpcyBhIHNoYW1lIGJlY2F1c2Ugd2UgY291bGQgaGF2ZSBpbmZlcnJlZCBsaWZlIHN0YWdlIGZyb20gbGVuZ3RoLiBBdCB0aGlzIHBvaW50LCBpdCBkb2Vzbid0IHNlZW0gd29ydGggd2hpbGUgdG8gdG9zcyBvdXQgcG90ZW50aWFsbHkgaGFsZiB0aGUgZGF0YSB0byBpbmNsdWRlIGVpdGhlciBvZiB0aG9zZSB2YXJpYWJsZXMuIEFsdGhvdWdoLCBJIG1heSByZXR1cm4gdG8gdGhpcyBkb3duIHRoZSByb2FkLgoKRmlyc3QsIGxldCdzIGNoZWNrIG91dCBhbGwgdGhlIHRheGEgd2UgaGF2ZSBpbiB0aGUgZGF0YToKCiMjIyBUYXhhIGxpc3QgLSBiZWZvcmUgZWRpdHMgey0gLnRhYnNldCAudGFic2V0LXBpbGxzfQoKIyMjIyBTcGVjaWVzIHstfQoKYGBge3IgZWNobyA9IEZBTFNFfQpjYXRjaC4xICU+JQogIHNlbGVjdChTcF9TY2llbnRpZmljTmFtZSwgU3BfQ29tbW9uTmFtZSkgJT4lCiAgcmVuYW1lKGBTY2llbnRpZmljIE5hbWVgID0gU3BfU2NpZW50aWZpY05hbWUsIGBDb21tb24gTmFtZWAgPSBTcF9Db21tb25OYW1lKSAlPiUKICBkaXN0aW5jdCgpICU+JQogIGFycmFuZ2UoYFNjaWVudGlmaWMgTmFtZWApICU+JQogIERUOjpkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgIGV4dGVuc2lvbnMgPSAnU2Nyb2xsZXInLAogICAgICAgICAgICAgICAgb3B0aW9ucyA9IGxpc3QoCiAgICAgICAgICAgICAgICAgIGRlZmVyUmVuZGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgc2Nyb2xsWSA9IDUwMCwKICAgICAgICAgICAgICAgICAgc2Nyb2xsZXIgPSBUUlVFKSkKYGBgCgojIyMjIEZhbWlseSB7LX0KCmBgYHtyIGVjaG8gPSBGQUxTRX0KY2F0Y2guMSAlPiUKICBzZWxlY3QoRmFtX1NjaWVudGlmaWNOYW1lLCBGYW1fQ29tbW9uTmFtZSkgJT4lCiAgcmVuYW1lKGBTY2llbnRpZmljIE5hbWVgID0gRmFtX1NjaWVudGlmaWNOYW1lLCBgQ29tbW9uIE5hbWVgID0gRmFtX0NvbW1vbk5hbWUpICU+JQogIGRpc3RpbmN0KCkgJT4lCiAgYXJyYW5nZShgU2NpZW50aWZpYyBOYW1lYCkgJT4lCiAgRFQ6OmRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgZXh0ZW5zaW9ucyA9ICdTY3JvbGxlcicsCiAgICAgICAgICAgICAgICBvcHRpb25zID0gbGlzdCgKICAgICAgICAgICAgICAgICAgZGVmZXJSZW5kZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgICBzY3JvbGxZID0gNTAwLAogICAgICAgICAgICAgICAgICBzY3JvbGxlciA9IFRSVUUpKQpgYGAKClRoZSBkaXNjcmVwYW5jeSBiZXR3ZWVuIHNwZWNpZXMgY29tbW9uIGFuZCBzY2llbnRpZmljIG5hbWVzIGhhcyB0byBkbyB3aXRoIHRoZSBjYXNlcyB3aGVyZSBmaXNoIHdlcmUgZ2l2ZW4gdW5pZGVudGlmaWVkIG9yIGp1dmVuaWxlIGxhYmVscy4gTm90aGluZyB0byBmaXggaGVyZSBidXQgd2UnbGwganVzdCBtYWtlIHN1cmUgdG8gdXNlIHNjaWVudGlmaWMgbmFtZXMgaW4gYW5hbHlzZXMuCgpJIGFsc28gbm90aWNlIGEgY291cGxlIG9mIGNhc2VzIHdoZXJlIHNwZWNpZXMgYXJlIGNhbGxlZCBzb21ldGhpbmcgJ29yJyBzb21ldGhpbmcgZWxzZToKCjEuICBBbmlzYXJjaHVzIG1lZGl1cyBvciBMdW1wZW51cyBmYWJyaWNpaQoyLiAgT3NtZXJpZGFlIG9yIENsdXBpZGFlIChtaXNzcGVsbGVkKQoKTG9va2luZyBhdCB0aGUgZmFtaWx5IHRhYmxlLCB3ZSBkb24ndCBzZWUgJ09zbWVyaWRhZSBvciBDbHVwZWlkYWUnLCBzbyBJIHRoaW5rIHRoYXQgcmVwbGFjaW5nIHRoZXNlICdvcicgY2FzZXMgd2l0aCB0aGVpciBhc3NvY2lhdGVkIGZhbWlseSBzY2llbnRpZmljIG5hbWUgc2hvdWxkIHN1ZmZpY2UuCgpTcGVha2luZyBvZiB0aGUgZmFtaWx5IHRhYmxlLCBJIHNlZSB0aGF0IHRob3NlIG1pc3NpbmcgZGF0YSBzaG93IHVwIGFzIE5BJ3MuIFdlJ2xsIHRha2UgYSBsb29rIGF0IGl0IGFuZCBtYWtlIGEganVkZ21lbnQgY2FsbCBvbiBob3cgdG8gZGVhbCB3aXRoIHRoZS4KCkxhc3QsIEknbGwgYWxzbyBjcmVhdGUgYSBnZW51cyBjbGFzc2lmaWNhdGlvbiwgd2hpY2ggY291bGQgZW5kIHVwIGJlaW5nIHRoZSBsZXZlbCBhdCB3aGljaCB3ZSBkbyB0aGUgYW5hbHlzZXMsIGRlcGVuZGluZyBvbiB3aGF0IHRoYXQgbG9va3MgbGlrZS4KCkkgZG8gbm90IHNob3cgcmVzdWx0cyBvZiB0aGUgYmVsb3cgY29kZSwgYnV0IEkgcHJvdmlkZWQgYW4gZWRpdGVkIHRheGEgbGlzdCBhbmQgc2VlIGFsc28gY29tbWVudHMgZm9yIHN0ZXBzIHRha2VuLgoKYGBge3IgcmVzdWx0cyA9ICJoaWRlIn0KIyBDaGVjayBvdXQgdGhlIGNhc2VzIHdoZXJlIGZhbWlseSBpcyBtaXNzaW5nCmZpbHRlcihjYXRjaC4xLCBpcy5uYShGYW1fU2NpZW50aWZpY05hbWUpKQojIExvb2sgdXAgdGhlIHZpc2l0IGluZm8gZm9yIHRoZXNlIGNhc2VzCmZpbHRlcih2aXNpdHMsIEV2ZW50SUQgJWluJSBjYXRjaC4xJEV2ZW50SURbd2hpY2goaXMubmEoY2F0Y2guMSRGYW1fU2NpZW50aWZpY05hbWUpKV0pCiMgQ2hlY2sgb3V0IGV2ZXJ5dGhpbmcgZWxzZSBjYXVnaHQgZHVyaW5nIHRoZXNlIHZpc2l0cwpmaWx0ZXIoY2F0Y2guMSwgRXZlbnRJRCAlaW4lIGNhdGNoLjEkRXZlbnRJRFt3aGljaChpcy5uYShjYXRjaC4xJEZhbV9TY2llbnRpZmljTmFtZSkpXSkKIyBTaW5jZSB0aGVzZSBuaW5lIE5BcyBtYWtlIHVwIGEgc21hbGwgcG9ydGlvbiBvZiB0aGVpciBzYW1wbGVzLAojIFRoZSBzaW1wbGVzdCBzb2x2ZSBoZXJlIGlzIHRvIGp1c3QgcmVtb3ZlIHRoZSBkYXRhLgoKIyBDcmVhdGUgYSBuZXcgb2JqZWN0IGFmdGVyIGVkaXRzIG1hZGUgdG8gdGF4b25vbXkKY2F0Y2guMiA9IGNhdGNoLjEgJT4lCiAgIyBEcm9wIHRoZSBuaW5lIGluc3RhbmNlcyBvZiBOQSBjYXRjaAogIGRyb3BfbmEoRmFtX1NjaWVudGlmaWNOYW1lKSAlPiUKICAjIEZpbmQgdGhlICdvcicgc3BlY2llcyBhbmQgcmVwbGFjZSB3aXRoIEZhbV9TY2llbnRpZmljTmFtZSB2YWx1ZQogIG11dGF0ZShTcF9TY2llbnRpZmljTmFtZSA9IGlmZWxzZShzdHJfZGV0ZWN0KFNwX1NjaWVudGlmaWNOYW1lLCBwYXR0ZXJuID0gIiBvciAiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRmFtX1NjaWVudGlmaWNOYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTcF9TY2llbnRpZmljTmFtZSksCiAgICAgICAgICMgQ3JlYXRlIGdlbnVzIGNsYXNzIGJ5IHRha2luZyBmaXJzdCB3b3JkIG9mIFNwX1NjaWVudGlmaWNOYW1lCiAgICAgICAgIEdlbl9TY2llbnRpZmljTmFtZSA9IHdvcmQoU3BfU2NpZW50aWZpY05hbWUsIDEpKQpgYGAKCiMjIyBUYXhhIGxpc3QgLSBhZnRlciBlZGl0cyB7LSAudGFic2V0IC50YWJzZXQtcGlsbHN9CgojIyMjIFNwZWNpZXMgey19CgpgYGB7ciBlY2hvID0gRkFMU0V9CmNhdGNoLjIgJT4lCiAgc2VsZWN0KFNwX1NjaWVudGlmaWNOYW1lLCBTcF9Db21tb25OYW1lKSAlPiUKICByZW5hbWUoYFNjaWVudGlmaWMgTmFtZWAgPSBTcF9TY2llbnRpZmljTmFtZSwgYENvbW1vbiBOYW1lYCA9IFNwX0NvbW1vbk5hbWUpICU+JQogIGRpc3RpbmN0KCkgJT4lCiAgYXJyYW5nZShgU2NpZW50aWZpYyBOYW1lYCkgJT4lCiAgRFQ6OmRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgZXh0ZW5zaW9ucyA9ICdTY3JvbGxlcicsCiAgICAgICAgICAgICAgICBvcHRpb25zID0gbGlzdCgKICAgICAgICAgICAgICAgICAgZGVmZXJSZW5kZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgICBzY3JvbGxZID0gNTAwLAogICAgICAgICAgICAgICAgICBzY3JvbGxlciA9IFRSVUUpKQpgYGAKCiMjIyMgR2VudXMgey19CgpgYGB7ciBlY2hvID0gRkFMU0V9CmNhdGNoLjIgJT4lCiAgc2VsZWN0KGBTY2llbnRpZmljIE5hbWVgID0gR2VuX1NjaWVudGlmaWNOYW1lKSAlPiUKICBkaXN0aW5jdCgpICU+JQogIGFycmFuZ2UoYFNjaWVudGlmaWMgTmFtZWApICU+JQogIERUOjpkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgIGV4dGVuc2lvbnMgPSAnU2Nyb2xsZXInLAogICAgICAgICAgICAgICAgb3B0aW9ucyA9IGxpc3QoCiAgICAgICAgICAgICAgICAgIGRlZmVyUmVuZGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgc2Nyb2xsWSA9IDUwMCwKICAgICAgICAgICAgICAgICAgc2Nyb2xsZXIgPSBUUlVFKSkKYGBgCgojIyMjIEZhbWlseSB7LX0KCmBgYHtyIGVjaG8gPSBGQUxTRX0KY2F0Y2guMiAlPiUKICBzZWxlY3QoRmFtX1NjaWVudGlmaWNOYW1lLCBGYW1fQ29tbW9uTmFtZSkgJT4lCiAgcmVuYW1lKGBTY2llbnRpZmljIE5hbWVgID0gRmFtX1NjaWVudGlmaWNOYW1lLCBgQ29tbW9uIE5hbWVgID0gRmFtX0NvbW1vbk5hbWUpICU+JQogIGRpc3RpbmN0KCkgJT4lCiAgYXJyYW5nZShgU2NpZW50aWZpYyBOYW1lYCkgJT4lCiAgRFQ6OmRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgZXh0ZW5zaW9ucyA9ICdTY3JvbGxlcicsCiAgICAgICAgICAgICAgICBvcHRpb25zID0gbGlzdCgKICAgICAgICAgICAgICAgICAgZGVmZXJSZW5kZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgICBzY3JvbGxZID0gNTAwLAogICAgICAgICAgICAgICAgICBzY3JvbGxlciA9IFRSVUUpKQpgYGAKCiMjIEFidW5kYW5jZSBhbmQgb2NjdXJlbmNlCgojIyMgJ1VubWVhc3VyZWQnIGludG8gJ0NvdW50JwoKVGhlIGJlbG93IGNvZGUgY2hhbmdlcyB0aGUgJ1VubWVhc3VyZWQnIHBhcmFtZXRlciBpbnRvICdDb3VudCcgYWJ1bmRhbmNlOgoKYGBge3IgcmVzdWx0cyA9ICJoaWRlIn0KY2F0Y2guMyA9IG11dGF0ZShjYXRjaC4yLCBDb3VudCA9IGlmZWxzZShVbm1lYXN1cmVkID09IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBVbm1lYXN1cmVkKSkgJT4lCiAgc2VsZWN0KC1Vbm1lYXN1cmVkKSAjIHJlbW92ZSB1bnVzZWQgcGFyYW1ldGVyCmBgYAoKTm93IHdlIGNhbiBtYWtlIGdyYXBocyB0byBzZWUgd2hhdCBraW5kIG9mIGNhdGNoIHdlIGhhdmUuIEZvciBlYWNoIHRheGEgbGV2ZWwsIEknbGwgbWFrZSByYXcgYWJ1bmRhbmNlIGFuZCBmcmVxdWVuY3kgb2Ygb2NjdXJyZW5jZSBncmFwaHMuCgojIyMgVmlzdWFsaXppbmcgY2F0Y2ggZGF0YSB7LSAudGFic2V0IC50YWJzZXQtcGlsbHN9CgojIyMjIFNwZWNpZXMgey19CgpgYGB7ciBlY2hvID0gRkFMU0UsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gOH0KIyBTcGVjaWVzIGFidW5kYW5jZQpzcC5hYnVuID0gY2F0Y2guMyAlPiUKICBzdW1tYXJpc2UoQWJ1bmRhbmNlID0gc3VtKENvdW50KSwgLmJ5ID0gU3BfU2NpZW50aWZpY05hbWUpICU+JQogIG11dGF0ZShTcF9TY2llbnRpZmljTmFtZSA9IGZjdF9yZW9yZGVyKGFzLmZhY3RvcihTcF9TY2llbnRpZmljTmFtZSksIGRlc2MoQWJ1bmRhbmNlKSkpCiMgUGxvdApnZ3Bsb3QoZGF0YSA9IHNwLmFidW4sIGFlcyh4ID0gU3BfU2NpZW50aWZpY05hbWUsIHkgPSBBYnVuZGFuY2UpKSArCiAgZ2VvbV9jb2woKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IEFidW5kYW5jZSksIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgbGFicyh0aXRsZSA9ICdTcGVjaWVzIGFidW5kYW5jZScsIHggPSAnU3BlY2llcycpCiMgZ2dzYXZlKCJuZmFfc3BfYWJ1bl9yYXcucG5nIiwgcGxvdCA9IGxhc3RfcGxvdCgpLCBkZXZpY2UgPSAncG5nJywgcGF0aCA9IGZpbGUucGF0aChkaXIuZmlncykpCgojIFNwZWNpZXMgZnJlcXVlbmN5IG9mIG9jY3VycmVuY2UKc3AuZnJlcS5vY2N1ciA9IGxlZnRfam9pbihjYXRjaC4zLCBzZWxlY3QodmlzaXRzLCBWaXNpdElELCBFdmVudElEKSwgYnkgPSAiRXZlbnRJRCIpICU+JQogIHN1bW1hcmlzZShQcmVzZW5jZSA9IG5fZGlzdGluY3QoU3BfU2NpZW50aWZpY05hbWUpLCAuYnkgPSBjKFZpc2l0SUQsIFNwX1NjaWVudGlmaWNOYW1lKSkgJT4lCiAgc3VtbWFyaXNlKE9jY3VycmVuY2UgPSBzdW0oUHJlc2VuY2UpLCAuYnkgPSBTcF9TY2llbnRpZmljTmFtZSkgJT4lCiAgbXV0YXRlKFBlcmNfT2NjdXJyZW5jZSA9IHJvdW5kKE9jY3VycmVuY2UgLyBuX2Rpc3RpbmN0KHZpc2l0cyRWaXNpdElEKSAqIDEwMCwgMiksCiAgICAgICAgIFNwX1NjaWVudGlmaWNOYW1lID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFNwX1NjaWVudGlmaWNOYW1lKSwgZGVzYyhQZXJjX09jY3VycmVuY2UpKSkKIyBQbG90CmdncGxvdChkYXRhID0gc3AuZnJlcS5vY2N1ciwgYWVzKHggPSBTcF9TY2llbnRpZmljTmFtZSwgeSA9IFBlcmNfT2NjdXJyZW5jZSkpICsKICBnZW9tX2NvbCgpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQoUGVyY19PY2N1cnJlbmNlLCAxKSksIHNpemUgPSAyLCB2anVzdCA9IC0wLjUpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgICBsYWJzKHRpdGxlID0gJ1NwZWNpZXMgZnJlcXVlbmN5IG9mIG9jY3VycmVuY2UnLCB4ID0gJ1NwZWNpZXMnLCB5ID0gJ1BlcmNlbnQgb2NjdXJyZW5jZScpCiMgZ2dzYXZlKCJuZmFfc3BfZnJlcS1vY2N1ci5wbmciLCBwbG90ID0gbGFzdF9wbG90KCksIGRldmljZSA9ICdwbmcnLCBwYXRoID0gZmlsZS5wYXRoKGRpci5maWdzKSkKCiMgVGFibGUgb2Ygc3BlY2llcyBhYnVuZGFuY2UgYW5kIG9jY3VycmVuY2UKZnVsbF9qb2luKHNwLmFidW4sIHNwLmZyZXEub2NjdXIsIGJ5ID0gJ1NwX1NjaWVudGlmaWNOYW1lJykgJT4lCiAgc2VsZWN0KGBTY2llbnRpZmljIE5hbWVgID0gU3BfU2NpZW50aWZpY05hbWUsIGBQZXJjZW50IE9jY3VycmVuY2VgID0gUGVyY19PY2N1cnJlbmNlLCBBYnVuZGFuY2UpICU+JQogIGFycmFuZ2UoYFNjaWVudGlmaWMgTmFtZWApICU+JQogIERUOjpkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgIGV4dGVuc2lvbnMgPSAnU2Nyb2xsZXInLAogICAgICAgICAgICAgICAgb3B0aW9ucyA9IGxpc3QoCiAgICAgICAgICAgICAgICAgIGRlZmVyUmVuZGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgc2Nyb2xsWSA9IDUwMCwKICAgICAgICAgICAgICAgICAgc2Nyb2xsZXIgPSBUUlVFKSkKYGBgCgojIyMjIEdlbnVzIHstfQoKYGBge3IgZWNobyA9IEZBTFNFLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDh9CiMgR2VudXMgYWJ1bmRhbmNlCmdlbi5hYnVuID0gY2F0Y2guMyAlPiUKICBzdW1tYXJpc2UoQWJ1bmRhbmNlID0gc3VtKENvdW50KSwgLmJ5ID0gR2VuX1NjaWVudGlmaWNOYW1lKSAlPiUKICBtdXRhdGUoR2VuX1NjaWVudGlmaWNOYW1lID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKEdlbl9TY2llbnRpZmljTmFtZSksIGRlc2MoQWJ1bmRhbmNlKSkpCiMgUGxvdApnZ3Bsb3QoZGF0YSA9IGdlbi5hYnVuLCBhZXMoeCA9IEdlbl9TY2llbnRpZmljTmFtZSwgeSA9IEFidW5kYW5jZSkpICsKICBnZW9tX2NvbCgpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gQWJ1bmRhbmNlKSwgdmp1c3QgPSAtMC41LCBzaXplID0gMikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpICsKICBsYWJzKHRpdGxlID0gJ0dlbnVzIGFidW5kYW5jZScsIHggPSAnR2VudXMnKQojIGdnc2F2ZSgibmZhX2dlbl9hYnVuX3Jhdy5wbmciLCBwbG90ID0gbGFzdF9wbG90KCksIGRldmljZSA9ICdwbmcnLCBwYXRoID0gZmlsZS5wYXRoKGRpci5maWdzKSkKCiMgR2VudXMgZnJlcXVlbmN5IG9mIG9jY3VycmVuY2UKZ2VuLmZyZXEub2NjdXIgPSBsZWZ0X2pvaW4oY2F0Y2guMywgc2VsZWN0KHZpc2l0cywgVmlzaXRJRCwgRXZlbnRJRCksIGJ5ID0gIkV2ZW50SUQiKSAlPiUKICBzdW1tYXJpc2UoUHJlc2VuY2UgPSBuX2Rpc3RpbmN0KEdlbl9TY2llbnRpZmljTmFtZSksIC5ieSA9IGMoVmlzaXRJRCwgR2VuX1NjaWVudGlmaWNOYW1lKSkgJT4lCiAgc3VtbWFyaXNlKE9jY3VycmVuY2UgPSBzdW0oUHJlc2VuY2UpLCAuYnkgPSBHZW5fU2NpZW50aWZpY05hbWUpICU+JQogIG11dGF0ZShQZXJjX09jY3VycmVuY2UgPSByb3VuZChPY2N1cnJlbmNlIC8gbl9kaXN0aW5jdCh2aXNpdHMkVmlzaXRJRCkgKiAxMDAsIDIpLAogICAgICAgICBHZW5fU2NpZW50aWZpY05hbWUgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoR2VuX1NjaWVudGlmaWNOYW1lKSwgZGVzYyhQZXJjX09jY3VycmVuY2UpKSkKIyBQbG90IApnZ3Bsb3QoZGF0YSA9IGdlbi5mcmVxLm9jY3VyLCBhZXMoeCA9IEdlbl9TY2llbnRpZmljTmFtZSwgeSA9IFBlcmNfT2NjdXJyZW5jZSkpICsKICBnZW9tX2NvbCgpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQoUGVyY19PY2N1cnJlbmNlLCAxKSksIHNpemUgPSAyLCB2anVzdCA9IC0wLjUpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgICBsYWJzKHRpdGxlID0gJ0dlbnVzIGZyZXF1ZW5jeSBvZiBvY2N1cnJlbmNlJywgeCA9ICdHZW51cycsIHkgPSAnUGVyY2VudCBvY2N1cnJlbmNlJykKIyBnZ3NhdmUoIm5mYV9nZW5fZnJlcS1vY2N1ci5wbmciLCBwbG90ID0gbGFzdF9wbG90KCksIGRldmljZSA9ICdwbmcnLCBwYXRoID0gZmlsZS5wYXRoKGRpci5maWdzKSkKCgojIFRhYmxlIG9mIGdlbnVzIGFidW5kYW5jZSBhbmQgb2NjdXJyZW5jZQpmdWxsX2pvaW4oZ2VuLmFidW4sIGdlbi5mcmVxLm9jY3VyLCBieSA9ICdHZW5fU2NpZW50aWZpY05hbWUnKSAlPiUKICBzZWxlY3QoYFNjaWVudGlmaWMgTmFtZWAgPSBHZW5fU2NpZW50aWZpY05hbWUsIGBQZXJjZW50IE9jY3VycmVuY2VgID0gUGVyY19PY2N1cnJlbmNlLCBBYnVuZGFuY2UpICU+JQogIGFycmFuZ2UoYFNjaWVudGlmaWMgTmFtZWApICU+JQogIERUOjpkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgIGV4dGVuc2lvbnMgPSAnU2Nyb2xsZXInLAogICAgICAgICAgICAgICAgb3B0aW9ucyA9IGxpc3QoCiAgICAgICAgICAgICAgICAgIGRlZmVyUmVuZGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgc2Nyb2xsWSA9IDUwMCwKICAgICAgICAgICAgICAgICAgc2Nyb2xsZXIgPSBUUlVFKSkKYGBgCgojIyMjIEZhbWlseSB7LX0KCmBgYHtyIGVjaG8gPSBGQUxTRSwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA4fQojIEZhbWlseSBhYnVuZGFuY2UKZmFtLmFidW4gPSBjYXRjaC4zICU+JQogIHN1bW1hcmlzZShBYnVuZGFuY2UgPSBzdW0oQ291bnQpLCAuYnkgPSBGYW1fU2NpZW50aWZpY05hbWUpICU+JQogIG11dGF0ZShGYW1fU2NpZW50aWZpY05hbWUgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoRmFtX1NjaWVudGlmaWNOYW1lKSwgZGVzYyhBYnVuZGFuY2UpKSkKIyBQbG90CmdncGxvdChkYXQgPSBmYW0uYWJ1biwgYWVzKHggPSBGYW1fU2NpZW50aWZpY05hbWUsIHkgPSBBYnVuZGFuY2UpKSArCiAgZ2VvbV9jb2woKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IEFidW5kYW5jZSksIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgbGFicyh0aXRsZSA9ICdGYW1pbHkgYWJ1bmRhbmNlJywgeCA9ICdGYW1pbHknKQojIGdnc2F2ZSgibmZhX2ZhbV9hYnVuX3Jhdy5wbmciLCBwbG90ID0gbGFzdF9wbG90KCksIGRldmljZSA9ICdwbmcnLCBwYXRoID0gZmlsZS5wYXRoKGRpci5maWdzKSkKCiMgRmFtaWx5IGZyZXF1ZW5jeSBvZiBvY2N1cnJlbmNlCmZhbS5mcmVxLm9jY3VyID0gbGVmdF9qb2luKGNhdGNoLjMsIHNlbGVjdCh2aXNpdHMsIFZpc2l0SUQsIEV2ZW50SUQpLCBieSA9ICJFdmVudElEIikgJT4lCiAgc3VtbWFyaXNlKFByZXNlbmNlID0gbl9kaXN0aW5jdChGYW1fU2NpZW50aWZpY05hbWUpLCAuYnkgPSBjKFZpc2l0SUQsIEZhbV9TY2llbnRpZmljTmFtZSkpICU+JQogIHN1bW1hcmlzZShPY2N1cnJlbmNlID0gc3VtKFByZXNlbmNlKSwgLmJ5ID0gRmFtX1NjaWVudGlmaWNOYW1lKSAlPiUKICBtdXRhdGUoUGVyY19PY2N1cnJlbmNlID0gcm91bmQoT2NjdXJyZW5jZSAvIG5fZGlzdGluY3QodmlzaXRzJFZpc2l0SUQpICogMTAwLCAyKSwKICAgICAgICAgRmFtX1NjaWVudGlmaWNOYW1lID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKEZhbV9TY2llbnRpZmljTmFtZSksIGRlc2MoUGVyY19PY2N1cnJlbmNlKSkpCiMgUGxvdApnZ3Bsb3QoZGF0YSA9IGZhbS5mcmVxLm9jY3VyLCBhZXMoeCA9IEZhbV9TY2llbnRpZmljTmFtZSwgeSA9IFBlcmNfT2NjdXJyZW5jZSkpICsKICBnZW9tX2NvbCgpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQoUGVyY19PY2N1cnJlbmNlLCAxKSksIHNpemUgPSAyLCB2anVzdCA9IC0wLjUpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgICBsYWJzKHRpdGxlID0gJ0ZhbWlseSBmcmVxdWVuY3kgb2Ygb2NjdXJyZW5jZScsIHggPSAnRmFtaWx5JywgeSA9ICdQZXJjZW50IG9jY3VycmVuY2UnKQojIGdnc2F2ZSgibmZhX2ZhbV9mcmVxLW9jY3VyLnBuZyIsIHBsb3QgPSBsYXN0X3Bsb3QoKSwgZGV2aWNlID0gJ3BuZycsIHBhdGggPSBmaWxlLnBhdGgoZGlyLmZpZ3MpKQoKIyBUYWJsZSBvZiBmYW1pbHkgYWJ1bmRhbmNlIGFuZCBvY2N1cnJlbmNlCmZ1bGxfam9pbihmYW0uYWJ1biwgZmFtLmZyZXEub2NjdXIsIGJ5ID0gJ0ZhbV9TY2llbnRpZmljTmFtZScpICU+JQogIHNlbGVjdChgU2NpZW50aWZpYyBOYW1lYCA9IEZhbV9TY2llbnRpZmljTmFtZSwgYFBlcmNlbnQgT2NjdXJyZW5jZWAgPSBQZXJjX09jY3VycmVuY2UsIEFidW5kYW5jZSkgJT4lCiAgYXJyYW5nZShgU2NpZW50aWZpYyBOYW1lYCkgJT4lCiAgRFQ6OmRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgZXh0ZW5zaW9ucyA9ICdTY3JvbGxlcicsCiAgICAgICAgICAgICAgICBvcHRpb25zID0gbGlzdCgKICAgICAgICAgICAgICAgICAgZGVmZXJSZW5kZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgICBzY3JvbGxZID0gNTAwLAogICAgICAgICAgICAgICAgICBzY3JvbGxlciA9IFRSVUUpKQpgYGAKCmBgYHtyfQojIFZpZXcgdGhlIGNvbW1vbiBuYW1lcyBmb3IgcmFyZSBHZW51c2VzLAojIGkuZS4sIG9jY3VyaW5nIGluIDwwLjI1JSBvZiB2aXNpdHMgKDYgb3IgZmV3ZXIgdmlzaXRzKQojIFRoZXNlIGluY2x1ZGUgMzQgZGlmZmVyZW50IHRheGEKZ2VuLmZyZXEub2NjdXIgJT4lCiAgZmlsdGVyKFBlcmNfT2NjdXJyZW5jZSA8IDAuMjUpICU+JQogIG11dGF0ZShHZW5fU2NpZW50aWZpY05hbWUgPSBhcy5jaGFyYWN0ZXIoR2VuX1NjaWVudGlmaWNOYW1lKSkgJT4lCiAgc2VsZWN0KEdlbl9TY2llbnRpZmljTmFtZSkgJT4lCiAgYXJyYW5nZSgpICU+JQogIGtuaXRyOjprYWJsZSgpCgojIFRoZXJlIGFyZSAxMCBmYW1pbGllcyB0aGF0IG9jY3VyIGluIGxlc3MgdGhhbiAxJSBvZiB2aXNpdHMuCiMgV2Ugd2lsbCBjb25zaWRlciB0aGVzZSBvdXIgZXh0cmVtZSByYXJlIGNhc2VzIGFuZCByZW1vdmUgdGhlbSBmcm9tIHRoZSBkZiwKZmFtLmZyZXEub2NjdXIgJT4lCiAgZmlsdGVyKFBlcmNfT2NjdXJyZW5jZSA8IDEpICU+JQogIG11dGF0ZShGYW1fU2NpZW50aWZpY05hbWUgPSBhcy5jaGFyYWN0ZXIoRmFtX1NjaWVudGlmaWNOYW1lKSkgJT4lCiAgc2VsZWN0KEZhbV9TY2llbnRpZmljTmFtZSkgJT4lCiAgYXJyYW5nZSgpICU+JQogIGtuaXRyOjprYWJsZSgpCmBgYAoKIyAgey51bmxpc3RlZCAudW5udW1iZXJlZH0K